﻿using System;
using System.Drawing;

namespace SmartWallpaperChanger
{
    /// <summary>
    /// ImageResizer smartly resizes images to a given size.
    /// </summary>
    public class ImageResizer
    {
        private Size targetSize;

        #region Properties
        /// <summary>
        /// Gets or sets the desired target size. Links to target height/width.
        /// </summary>
        public Size TargetSize
        {
            get { return targetSize; }
            set { targetSize = value; }
        }

        /// <summary>
        /// Gets the desired target height as double.
        /// </summary>
        private double TargetHeightAsDouble
        {
            get { return (double)targetSize.Height; }
        }

        /// <summary>
        /// Gets the desired target width as double.
        /// </summary>
        private double TargetWidthAsDouble
        {
            get { return (double)targetSize.Width; }
        }

        #endregion

        /// <summary>
        /// Initializes a new ImageResizer with a default target size.
        /// </summary>
        public ImageResizer()
        {
            targetSize = new Size(100,100);
        }

        /// <summary>
        /// Initializes a new ImageResizer.
        /// </summary>
        /// <param name="targetSize">Desired target size.</param>
        public ImageResizer(Size targetSize)
        {
            this.targetSize = targetSize;
        }

        /// <summary>
        /// Resizes a bitmap to given size.
        /// </summary>
        /// <param name="source">Bitmap to resize.</param>
        /// <returns>Resized bitmap.</returns>
        public Bitmap Resize(Bitmap source)
        {
            try
            {
                Bitmap resizedImage = new Bitmap(TargetSize.Width, TargetSize.Height, System.Drawing.Imaging.PixelFormat.Format24bppRgb);
                resizedImage.SetResolution(source.HorizontalResolution, source.VerticalResolution);

                Graphics graphics = Graphics.FromImage(resizedImage);
                graphics.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.HighQualityBilinear;

                Size newSize = GetNewDimensions(source.Height, source.Width);

                int marginX = (newSize.Width - TargetSize.Width) / 2;
                int marginY = (newSize.Height - TargetSize.Height) / 2;

                graphics.DrawImage(source,
                        new Rectangle(-1 * marginX, -1 * marginY, newSize.Width, newSize.Height),
                        new Rectangle(0, 0, source.Width, source.Height),
                        GraphicsUnit.Pixel);


                source.Dispose();

                return resizedImage;
            }
            catch (Exception ex)
            {
                throw new InvalidOperationException("Resizing failed.", ex);
            }
        }

        #region Helper

        /// <summary>
        /// Resizes the image to fill the whole Screen.
        /// </summary>
        private Size GetNewDimensions(int imageHeight, int imageWidth)
        {
            try
            {
                Size currentSize = new Size(imageWidth, imageHeight);

                double offsetHeight = ((double)imageHeight / TargetHeightAsDouble);
                double offsetWidth = ((double)imageWidth / TargetWidthAsDouble);

                if (offsetHeight == offsetWidth)
                {
                    return ToTargetHeight(currentSize);
                }

                if (offsetHeight < 1)
                {
                    if (offsetWidth < 1)
                    {
                        if (offsetHeight < offsetWidth)
                        {
                            currentSize = ToTargetHeight(currentSize);
                        }
                        else
                        {
                            currentSize = ToTargetWidth(currentSize);
                        }
                    }
                    else
                    {
                        currentSize = ToTargetHeight(currentSize);
                    }
                }
                else if (offsetHeight > 1)
                {
                    if (offsetWidth > 1)
                    {
                        if (offsetHeight > offsetWidth)
                        {
                            currentSize = ToTargetWidth(currentSize);
                        }
                        else
                        {
                            currentSize = ToTargetHeight(currentSize);
                        }
                    }
                    else
                    {
                        currentSize = ToTargetWidth(currentSize);
                    }
                }

                offsetWidth = ((double)currentSize.Width / TargetWidthAsDouble);
                if (offsetWidth < 1)
                {
                    currentSize = ToTargetWidth(currentSize);
                }

                return currentSize;
            }
            catch (Exception ex)
            {
                throw new InvalidOperationException("Calculating new Size failed", ex);
            }
        }

        /// <summary>
        /// Sets the height to the target height.
        /// </summary>
        private Size ToTargetHeight(Size size)
        {
            double newHeight = TargetHeightAsDouble;
            double newWidth = ((double)size.Width * newHeight) / (double)size.Height;

            return new Size((int)Math.Ceiling(newWidth), (int)Math.Ceiling(newHeight));
        }

        /// <summary>
        /// Sets the width to the target width.
        /// </summary>
        private Size ToTargetWidth(Size size)
        {
            double newWidth = TargetWidthAsDouble;
            double newHeight = ((double)size.Height * newWidth) / (double)size.Width;

            return new Size((int)Math.Ceiling(newWidth), (int)Math.Ceiling(newHeight));
        }

        #endregion

    }
}
